package birdsong.comm;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Hashtable;

import birdsong.comm.ClientSideMessage.Type;

public class ServerCommImp extends Thread implements ServerComm {

	private static int SV_PORT = 8080;

	private Hashtable<String, Socket> clients_hashT;

	private Socket cl_socket;
	private ServerSocket sv_socket;

	private ObjectInputStream in;
	private ObjectOutputStream out;
	
	private ServerSideMessage ssm;

	public ServerCommImp() {
		clients_hashT = new Hashtable<String, Socket>();
	}

	@Override
	public void start() {
		try {
			sv_socket = new ServerSocket(SV_PORT);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("Server Socket Initialized! " + sv_socket);	

		try {
			cl_socket = sv_socket.accept();

			try {
				System.out.println("New connection: " + cl_socket);

				out = new ObjectOutputStream(cl_socket.getOutputStream());
				in = new ObjectInputStream(cl_socket.getInputStream());
				
				addClient();
				
				while (true) {
					getNextMessage();
					System.out.println(ssm.getClientNickname() + ": " + ssm.getPayload());
				}

			} catch (Exception e) {
				// TODO: handle exception
				e.printStackTrace();
			}

			finally {
				// TODO: handle exception
				try {
					System.out.println("Servidor a fechar socket do cliente");
					cl_socket.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		finally{
			try {
				sv_socket.close();
			} catch (IOException e) {
				// TODO: handle exception
				e.printStackTrace();
			}
		}
	}

	private synchronized void addClient() {
		// TODO Auto-generated method stub
		getNextMessage();
		clients_hashT.put(ssm.getClientNickname(), cl_socket);
	}

	@Override
	public ServerSideMessage getNextMessage() {
		// TODO Auto-generated method stub
		try {
			ssm = (ServerSideMessage) in.readObject();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return ssm;
	}

	@Override
	public boolean hasNextMessage() {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public void sendBirdsongMessage(String fromNickname, String toNickname,
			String birdsongMessage) {
		// TODO Auto-generated method stub
		try {
			out.writeObject(new ClientSideMessageImp(fromNickname, Type.BIRDSONG_MESSAGE, birdsongMessage));
			out.flush();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	@Override
	public void sendNewFollower(String toNickname, String newFollower) {
		// TODO Auto-generated method stub
		try {
			out.writeObject(new ClientSideMessageImp(newFollower, Type.FOLLOWER, toNickname));
			out.flush();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	@Override
	public void sendNewUnfollow(String toNickname, String unfollower) {
		// TODO Auto-generated method stub
		try {
			out.writeObject(new ClientSideMessageImp(unfollower, Type.FOLLOWER, toNickname));
			out.flush();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	@Override
	public void sendError(String toNickname, String error) {
		// TODO Auto-generated method stub

	}

	@Override
	public void sendClientConnected(String toNickname, String connectedNickname) {
		// TODO Auto-generated method stub
		try {
			out.writeObject(new ClientSideMessageImp(connectedNickname, Type.FOLLOWER, toNickname));
			out.flush();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	@Override
	public void sendClientDisconnected(String toNickname,
			String disconnectedNickname) {
		// TODO Auto-generated method stub
		try {
			out.writeObject(new ClientSideMessageImp(disconnectedNickname, Type.FOLLOWER, toNickname));
			out.flush();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	@Override
	public boolean clientIsConnected(String nickname) {
		// TODO Auto-generated method stub
		if (clients_hashT.containsKey(nickname))
			return !clients_hashT.get(nickname).isClosed();
		return false;
	}

	@Override
	public void disconnectClient(String nickname) {
		// TODO Auto-generated method stub
		if (clients_hashT.containsKey(nickname))
			try {
				clients_hashT.get(nickname).close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	}
}
